package ink.metoo.gude.module.security.service.impl

import ink.metoo.gude.handler.ApiException
import ink.metoo.gude.model.ApiStatus
import ink.metoo.gude.module.security.domain.ddl.VerificationCode
import ink.metoo.gude.module.security.repository.VerificationCodeRepository
import ink.metoo.gude.module.security.service.VerificationCodeService
import ink.metoo.gude.util.SecureCodeUtils
import ink.metoo.gude.util.logger
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import java.time.Duration
import java.time.Instant

@Service
class VerificationCodeServiceImpl(private val verificationCodeRepository: VerificationCodeRepository) :
    VerificationCodeService {

    val log = logger()

    override fun getVerificationCode(key: String, type: String): String? {
        val verificationCode = verificationCodeRepository.findLastVerificationCode(key, type) ?: return null
        val createDate = verificationCode.createDate ?: return null
        val seconds = Duration.between(createDate.toInstant(), Instant.now()).seconds
        if (seconds < VALIDITY && verificationCode.invalidity != true) {
            return verificationCode.code
        }
        return null
    }


    @Transactional
    override fun restVerificationCode(key: String, type: String): String {
        var verificationCode = verificationCodeRepository.findLastVerificationCode(key, type)
        val secureCode = SecureCodeUtils.generateSecureCode(6)
        if (verificationCode != null) {
            val createDate = verificationCode.createDate!!
            val seconds = Duration.between(createDate.toInstant(), Instant.now()).seconds
            if (seconds < COOL_DOWN) {
                throw ApiException(ApiStatus.S_3001)
            }
        }
        verificationCode = VerificationCode()
        verificationCode.key = key
        verificationCode.type = type
        verificationCode.code = secureCode
        verificationCode.invalidity = false
        verificationCodeRepository.save(verificationCode)

        log.debug("rest verification code { ${verificationCode.code} } for type ($type): $key")
        return verificationCode.code!!
    }

    @Transactional
    override fun clearVerificationCode(key: String, type: String) {
        val verificationCode = verificationCodeRepository.findLastVerificationCode(key, type) ?: return
        verificationCode.invalidity = true
        verificationCodeRepository.save(verificationCode)
        log.debug("clear verification code for key: $key($type)")
    }

    companion object {

        private const val VALIDITY = 120L
        private const val COOL_DOWN = 60L

    }

}
